#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <string.h>
#include <sys/un.h> 
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h> 
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <math.h>


#include "configuracion.h"
#include "constantes.h"
#include "estructuras.h"
#include "cache.h"
#include "estadisticas.h"


#define SIZE_CACHE 10

extern chs glChs;
extern Sector cache[ SIZE_CACHE ];
extern int glCache;
extern double glTiempoCache;
extern int glRPM;

int sectoresTotales(chs datosChs) {

	int resultado;

	resultado = datosChs.cabezal * datosChs.cilindros * datosChs.sectores;

	return resultado;
}


int capacidadTotal(chs datosChs, int sizeSector) {
	return sectoresTotales(datosChs)*sizeSector;   
}

/* chs: se le pasa una direccion logica y devuelve la pista correspondiente */
int calculaChs(int sector) {
	if (sector == -1) { return -1; }
	return sector/4;
}

/* Estadisticas VDA */

double EstadisticasCache(int cantAccesos, int cantHit)
{
	double resultado = 0;
	
	/*
	 *********************
	 DESARROLLO DE FUNCION
	 *********************
	 */
	if(cantAccesos != 0)
	{
		resultado = (cantHit/cantAccesos);
	}
	
	/* devuelve resultado de la funcion */
	return resultado;
}

double rps(int rpm)
{
	return rpm/60;
}

double sectoresPorSegundo(chs auxChs, int rpm)
{
	return sectoresTotales(auxChs)/rps(rpm);
}

double tasaTransferencia(chs auxChs, int rpm, int sizeSector)
{
	return sectoresPorSegundo(auxChs, rpm)*sizeSector;
}

	
double segundosPorVuelta(int rpm)
{
	return 1/rps(rpm);
}

double tiempoRotacional(chs auxChs, int rpm)/* Lo devuelve en ms */
{
	return (1000* /* para pasarlo a ms */segundosPorVuelta(rpm))/auxChs.sectores;
}

double peorTiempoBusqueda(chs datosChs, int rpm) /* Lo devuelve en ms */
{
	return sectoresTotales(datosChs)*segundosPorVuelta(rpm)*1000 /* Para que sean ms */;
}

double medioTiempoBusqueda(chs datosChs, int rpm) /* Lo devuelve en ms */
{
	return peorTiempoBusqueda(datosChs, rpm)/2;
}

double tiempoMedioCache(double tiempoAccesoCache)
{
	return (tiempoAccesoCache*10)/2;
}

int getCilindro(int pos, chs auxChs)
{
	int resultado;

	resultado = pos/auxChs.sectores +1;

	return resultado;
}

int ultimoSector( int cilindro, chs auxChs )
{
	int resultado;

	resultado = (cilindro -1)* auxChs.sectores;
	resultado = resultado + auxChs.sectores -1;

	return resultado;
}

int primerSector( int auxSector, chs auxChs )
{
	int resultado;

	resultado = auxSector + auxChs.sectores;

	return resultado;

}

char* readSector(unsigned int numsector){
	
	char *read;
	int i;
	
	read=(char *)malloc(512);
	
	for(i=0;i<512;i++){
		read[i]=data[i+numsector*512];
	}
	
	return read;
}


int writeSector(unsigned int numsector,char* data_sector){
	
	int i;
	char aux;
	
	for(i=0;i<512;i++){
		data[i+numsector*512]=data_sector[i];
	}
	
	msync(data[i+numsector*512],512,MS_SYNC);
}	

void imprimirSector(unsigned int numsector){

	char* read;
	int i;
	
	read=malloc(512);

	strcpy(read,readSector(numsector));	
	for(i=0;i<512;i++){
		printf("%c",read[i]);
	}
	
	free(read);
	
}		

void clean(int sector1,int sector2){

   int i,aux;
   char data_sector[512];
    
   
   aux=sector1;
   
   for(i=0;i<512;i++){
      data_sector[i]="0";
   }
   
   while(aux!=sector2){
      for(i=0;i<8;i++){
         writeSector((aux-1)*512,data_sector);
      }
      aux++;
   }
  
}	

int trace(int vector[],int posicionCabezal,chs glChs,int glCache, double glTiempoCache,int glRPM){

	int i,f;
	int auxSectorBuscado;
	sectoresIntermedios listaSectoreYTiempos;

	i=0;
	while( i < 5  )
	{
		auxSectorBuscado = vector[i];
		if(vector[i] != -1)
		{	            
		   auxSectorBuscado = vector[i];
		   listaSectoreYTiempos = SectoresIntermedios(posicionCabezal,auxSectorBuscado,glChs,glCache, glTiempoCache, glRPM);
		   if(listaSectoreYTiempos.enCache == 0)
		   {
			  printf("SECTORES LEIDOS: ");
			  for( f = 0;f < listaSectoreYTiempos.tamanioVector;f++)
			  {
				 printf("%d |", listaSectoreYTiempos.ptrSectoresLeidos[f]);
			  }
			  printf("\n");
		   }
		   else
		   {
			  printf("SECTORES LEIDOS: %d - En cache\n", auxSectorBuscado);
		   }

		   printf("TIEMPO CONSUMIDO: %f ms\n",listaSectoreYTiempos.tiempoDeAcceso);
		   posicionCabezal=vector[i];
 
		}
		i++;
	}  
	
	return posicionCabezal;

}

sectoresIntermedios SectoresIntermedios(int posActual, int auxSectorBuscado, chs auxChs,int conCache, double tiempoCache, int rpm)
{
	sectoresIntermedios resultadoSectoresLeidos;
	int a, tamanioMem;

	int *sectoresLeidos;

	resultadoSectoresLeidos.enCache = 0;
	tamanioMem = 0;
	a=0;
	
	if(posActual > auxSectorBuscado)
	{
		tamanioMem = 4*2;
		sectoresLeidos = (int*) malloc(tamanioMem); /* mem para este y el que viene */
		posActual = 0;
		sectoresLeidos[a] = posActual;
		a++;
	}
	else
	{
		tamanioMem = 4;
		sectoresLeidos = (int*) malloc (tamanioMem); /* mem para el que viene */
	}


	while(getCilindro(posActual, auxChs) != getCilindro(auxSectorBuscado, auxChs))
	{
		posActual = primerSector(posActual,auxChs);
		sectoresLeidos[a] = posActual;
		a++;
		
		tamanioMem = tamanioMem + sizeof(int);
		sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem );

	}

	if(posActual > auxSectorBuscado)
	{
		while(posActual <= ultimoSector( getCilindro(auxSectorBuscado,auxChs), auxChs )) {
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;

			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc( sectoresLeidos, tamanioMem + sizeof(int));
		}
		posActual = posActual - auxChs.sectores;

		while(posActual <= auxSectorBuscado) {
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;

			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
		}

	}
	else
	{
		while(posActual != auxSectorBuscado )
		{
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;
			
			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
		}
	}

	resultadoSectoresLeidos.tamanioVector = a;
	resultadoSectoresLeidos.ptrSectoresLeidos = sectoresLeidos;

	if(conCache == 1)
	{
		if(estaEnCache(auxSectorBuscado))
		{
			int auxPos = posicionCache(auxSectorBuscado);

			resultadoSectoresLeidos.tiempoDeAcceso = (auxPos+1)*tiempoCache;

			resultadoSectoresLeidos.enCache = 1;
		}
		else
		{
			resultadoSectoresLeidos.tiempoDeAcceso = (tiempoCache*10) + a*tiempoRotacional(auxChs,rpm);
		}
	}
	else
	{
		resultadoSectoresLeidos.tiempoDeAcceso = a*tiempoRotacional(auxChs,rpm);
	}
	
	/*TODO despues de usar la funcion hay que liberar memoria*/
	return resultadoSectoresLeidos;
	
}
